package com.jie.filter;

import com.alibaba.fastjson2.JSON;
import com.jie.constants.RedisSessionConstants;
import com.jie.dto.UserDetailDTO;
import com.jie.exception.BizException;
import com.jie.service.impl.RedisService;
import com.jie.service.impl.UserDetailsServiceImpl;
import com.jie.utils.JwtTokenUtil;
import com.jie.utils.UserUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * JWT登录授权过滤器
 *
 * @author 2021/12/30
 */
public class JwtAuthencationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${jwt.refreshTime}")
    private Long refreshTime;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = httpServletRequest.getHeader(tokenHeader);
        //根据请求头是否为空或者开头是不是我们配置的负载开头
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            //截取authtoken
            String authToken = authHeader.substring(tokenHead.length());
            // 解析Token
            Claims claims = null;
            try {
                claims = jwtTokenUtil.parseToken(authToken);
            } catch (Exception e) {
                throw new BizException("令牌非法");
            }
            // 查询Redis中的用户信息
            String key = RedisSessionConstants.USER_LOGIN_INFO + claims.getSubject();
            String userInfoJSON = redisTemplate.opsForValue().get(key);
            UserDetailDTO userDetailDTO = JSON.parseObject(userInfoJSON, UserDetailDTO.class);
            // 令牌登出
            if (userDetailDTO == null) {
                throw new BizException("令牌登出，需要重新登录");
            }
            // 判断是否需要刷新令牌
            Long expireTime = redisTemplate.getExpire(key);
            if (expireTime != null && expireTime < refreshTime) {
                throw new BizException("令牌待刷新");
            }
            // 将用户信息存入security上下文
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(userDetailDTO, null, userDetailDTO.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}
